package com.google.code.twiddling.core.command.builtin;

import com.google.code.twiddling.core.command.AbstractCommand;
import com.google.code.twiddling.core.command.CommandContext;

import java.io.StringWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.IOException;
import java.io.Writer;
import java.io.Reader;

/**
 * //TODO: need to improve, do not call OS grep drectly, rewrite GrepCommand to support a safe grep 
 * Super class for OS Command, like ls, grep, find, sed, awk, etc...
 *
 * @author <a href="mailto:yy.young@gmail.com">Young Yang</a>
 * @create Dec 12, 2008 10:42:38 AM
 */
public abstract class OSCommand extends AbstractCommand{

    /**
     * Command to get usage message
     * @return cmd string
     */
    protected abstract String[] getUsageCommand();

    /**
     * Command to get help message
     * @return cmd string
     */
    protected abstract String[] getHelpCommand();

    /**
     * OS command to run in OS
     * @param context command context
     * @return command string
     */
    protected abstract String[] getOSCommand(CommandContext context);


    public void doExecute(CommandContext context) throws Exception {
        String result = runCommand(getOSCommand(context));
        PrintWriter out = context.getIO().getOut();
        out.println(result);
    }

    public String shortDescription() {
        try {
            return runCommand(getUsageCommand());
        }
        catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    public void displayHelp(CommandContext context) {
        try {
            String result = runCommand(getHelpCommand());
            PrintWriter out = context.getIO().getOut();
            out.println(result);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    public String runCommand(String[] cmdString) throws Exception{
        Process process = Runtime.getRuntime().exec(cmdString);
        int exitValue = process.waitFor();
        InputStream in = process.getInputStream();
        if(exitValue != 0) { // exit 0 while normal exit
            in = process.getErrorStream();
        }
        StringWriter sw = new StringWriter();
        InputStreamReader input = new InputStreamReader(in);
        copy(input, sw);
        in.close();
        process.destroy();
        return sw.toString();
    }

    public static int copy(Reader input, Writer output) throws IOException {
        char[] buffer = new char[1024];
        int count = 0;
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
            count += n;
        }
        return count;
    }
}
